package com.llcbenwu.security;

import cn.hutool.core.util.ObjectUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.provider.token.*;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * 认证服务器
 * @author lilinchun
 * @date 2021/11/12 0012 17:06
 */

@Configuration
@EnableAuthorizationServer
//public class LlcAuthorizationServerConfig  {
public class LlcAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {


    @Resource
    private AuthenticationManager authenticationManager;

    @Resource
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    @Resource
    private UserDetailsService userDetailsService;

    @Autowired(required = false)
    private JwtAccessTokenConverter jwtAccessTokenConverter;

    @Autowired(required = false)
    private TokenEnhancer jwtTokenEnhancer;

    @Resource
    private TokenStore tokenStore;


        /**
     * 如果没有类继承AuthorizationServerConfigurerAdapter那么系统会自动帮助你配置完成，但是继承了这个类只能自己配置
     * @param endpoints
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
                .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST)
                //指定使用的TokenStore，tokenStore用来存取token，默认使用InMemoryTokenStore
                .tokenStore(tokenStore)
                .authenticationManager(authenticationManager)
                .userDetailsService(userDetailsService);

        if(jwtAccessTokenConverter !=null&& ObjectUtil.isNotEmpty(jwtTokenEnhancer)  ){
            //配置增强器链
            // 并利用增强器链将生成jwt的TokenEnhancer（jwtAccessTokenConverter）
            // 和我们扩展的TokenEnhancer设置到token的生成类中
            TokenEnhancerChain enhancerChain=new TokenEnhancerChain();
            List<TokenEnhancer> enhancers=new ArrayList<>();
            enhancers.add(jwtAccessTokenConverter);
            enhancers.add(jwtTokenEnhancer);
            enhancerChain.setTokenEnhancers(enhancers);
            endpoints.tokenEnhancer(enhancerChain)
            .accessTokenConverter(jwtAccessTokenConverter);

//            endpoints.accessTokenConverter(jwtAccessTokenConverter);

        }
    }




    /**
     * 这里是配置一个client_id 和clent_secret
     * @param clients
     * @throws Exception
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        //指放在内存
        clients.inMemory()
                //设置client-id和client-secret，注意client-secret必须要进行加密处理
                .withClient("user")
                .secret(bCryptPasswordEncoder.encode("user"))
//                .secret("user")
                //发出去的令牌过期时间单位秒
                .accessTokenValiditySeconds(7200)
                //指定授权模式（指定其中一种，其他的几种就不能进行授权）
                .authorizedGrantTypes("refresh_token", "password")
                //配置了这个参数发请求就可以不用带scopes，如果配就必须是这三者中的一个
                .scopes("all", "read", "write");


    }


    /***
     * 用来打印一下密码，因为数据spring-security-oauth要求这个密码必须被加密过
     * @param args
     */
    public static void main(String[] args) {
        PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        System.out.println(passwordEncoder.encode("123456"));
    }
}
